package evaluator

import (
	"errors"
	"fmt"
	"quant/backend/constants"
	"quant/backend/entity"
	"sort"
	"strings"

	"github.com/duke-git/lancet/v2/convertor"
	"github.com/duke-git/lancet/v2/maputil"
)

type Evaluator struct {
	dailyEntities []entity.DailyEntity
	configMap     map[string]string
}

// NewEvaluator 创建评估器
func NewEvaluator(entities []entity.DailyEntity, m map[string]string) (*Evaluator, error) {
	// 把日行情列表按时间降序排序
	sort.SliceStable(entities, func(i, j int) bool {
		return entities[i].Time > entities[j].Time
	})
	if len(entities) <= 0 {
		return nil, errors.New("日行情列表为空")
	}

	var keys = []string{"min_turnout_rate", "max_turnout_rate", "min_amount", "max_amount", "min_price", "max_price"}
	for _, key := range keys {
		if !maputil.HasKey(m, key) {
			return nil, fmt.Errorf("配置项 %s 缺失", key)
		}
	}
	return &Evaluator{
		dailyEntities: entities,
		configMap:     m,
	}, nil
}

// EvalIsST 检查是否是 ST 股
// true: 表示是 ST 股票
// false: 表示不是 ST 股票
func (eval *Evaluator) EvalIsST() bool {
	if strings.Contains(eval.dailyEntities[0].StockName, "ST") {
		return true
	}
	return false
}

// EvalIs68 判断是否是科创板，注意：股票代码前缀：60:上证主板  68:上证科创板  00:深证主板  30: 深圳创业板
// true: 表示是
// false: 表示不是
func (eval *Evaluator) EvalIs68() bool {
	if strings.HasPrefix(eval.dailyEntities[0].StockCode, "68") {
		return true
	}
	return false
}

// EvalTurnoutRate 检查上个交易日股票换手率是否在 最低换手率 和 最高换手率 之间
// true: 表示有效，在允许范围内
// false: 表示无效，不在允许范围内
func (eval *Evaluator) EvalTurnoutRate() bool {
	minTurnoutRate, _ := convertor.ToFloat(eval.configMap["max_turnout_rate"])
	maxTurnoutRate, _ := convertor.ToFloat(eval.configMap["min_turnout_rate"])
	if eval.dailyEntities[0].TurnoutRate >= minTurnoutRate && eval.dailyEntities[0].TurnoutRate <= maxTurnoutRate {
		return true
	}
	return false
}

// EvalPrice 上个交易日股价是否在 最低股价 和 最高股价 之间
// true: 表示有效，在允许范围内
// false: 表示无效，不在允许范围内
func (eval *Evaluator) EvalPrice() bool {
	minPrice, _ := convertor.ToFloat(eval.configMap["min_price"]) // 最低股价
	maxPrice, _ := convertor.ToFloat(eval.configMap["max_price"]) // 最高股价
	// if eval.dailyEntities[0].Open < eval.dailyEntities[0].Close || eval.dailyEntities[0].PreClose > maxPrice {
	// 	return false
	// }
	if eval.dailyEntities[0].Close > minPrice && eval.dailyEntities[0].Close < maxPrice {
		return true
	}
	return false
}

// EvalAmount 总市值是否在 最小总市值 和 最大总市值 之间
// true: 表示有效，在允许范围内
// false: 表示无效，不在允许范围内
func (eval *Evaluator) EvalAmount() bool {
	minAmount, _ := convertor.ToFloat(eval.configMap["min_amount"]) // 最小总市值(亿元)
	maxAmount, _ := convertor.ToFloat(eval.configMap["max_amount"]) // 最大总市值(亿元)
	if eval.dailyEntities[0].TotalAmount >= constants.BaseAmount*minAmount && eval.dailyEntities[0].TotalAmount <= constants.BaseAmount*maxAmount {
		return true
	}
	return false
}

// EvalMacd 检查MACD是否在上升，红色还是绿色，
// 注意：（买入时，最好确保MACD在绿色，卖出时，确保MACD在红色）
// 返回：true 表示在涨，false 表示在跌
func (eval *Evaluator) EvalMacd() bool {
	isRed := false
	if eval.dailyEntities[0].Macd > 0 {
		isRed = true
	}
	if isRed {
		if (eval.dailyEntities[1].Macd < 0 || eval.dailyEntities[2].Macd < 0) &&
			eval.dailyEntities[0].Macd > eval.dailyEntities[1].Macd &&
			eval.dailyEntities[1].Macd > eval.dailyEntities[2].Macd {
			return true
		}
	} else {
		if eval.dailyEntities[0].Macd > eval.dailyEntities[1].Macd {
			return true
		}
	}
	return false
}

func (eval *Evaluator) EvalKDJ() bool {
	// 1.K与D值永远介于0到100之间。D大于80时，行情呈现超买现象。D小于20时，行情呈现超卖现象。
	// 2.上涨趋势中，K值大于D值，K线向上突破D线时，为买进信号。下跌趋势中，K值小于D值，K线向下跌破D线时，为卖出信号。
	// 3.KD指标不仅能反映出市场的超买超卖程度，还能通过交叉突破发出买卖信号。
	// 4.KD指标不适于发行量小、交易不活跃的股票，但是KD指标对大盘和热门大盘股有极高准确性。
	// 5.当随机指标与股价出现背离时，一般为转势的信号。
	// 6.K值和D值上升或者下跌的速度减弱，倾斜度趋于平缓是短期转势的预警信号。
	if eval.dailyEntities[0].J > eval.dailyEntities[1].J &&
		eval.dailyEntities[0].J > eval.dailyEntities[0].D {
		return true
	}
	return false
}
